package com.pzhu.dormitory.config;


import cn.hutool.json.JSONUtil;
import com.pzhu.dormitory.dto.UserDTO;
import com.pzhu.dormitory.entity.UserEntity;
import com.pzhu.dormitory.service.UserService;
import com.pzhu.dormitory.utils.PurviewFilter;
import com.pzhu.dormitory.utils.Rb;
import com.pzhu.dormitory.utils.RestAuthenticationEntryPoint;
import com.pzhu.dormitory.utils.RestfulAccessDeniedHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


/**
 * SpringSecurity的配置
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final UserService userservice;
    private final RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    public SecurityConfig(UserService userservice, RestfulAccessDeniedHandler restfulAccessDeniedHandler, RestAuthenticationEntryPoint restAuthenticationEntryPoint) {
        this.userservice = userservice;
        this.restfulAccessDeniedHandler = restfulAccessDeniedHandler;
        this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()
                .disable()
                .authorizeRequests()
                // 允许对于网站静态资源的无授权访问
                .antMatchers(HttpMethod.GET,
                        "/favicon.ico",
                        "/**/*.css",
                        "/swagger-resources/**",
                        "/v2/api-docs/**",
                        "webjars/**",
                        "/**/**",
                        "/**/*.js", "/**/*.png"
                )
                .permitAll()
                // 对登录注册要允许匿名访问
                .antMatchers("/index/login", "/practive/user/register")
                .permitAll()
                //跨域请求会先进行一次options请求
                .antMatchers(HttpMethod.OPTIONS)
                .permitAll()
                .anyRequest()// 除上面外的所有请求全部需要鉴权认证
                .authenticated();
        httpSecurity
                .formLogin()
                .loginPage("/index/login")
                .loginProcessingUrl("/login")
                .successHandler((httpServletRequest, response, authentication) -> {
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json");
                    response.getWriter().println(JSONUtil.parse(Rb.a().success().withMsg("登录成功").build()));
                    response.getWriter().flush();
                })
                .failureHandler((httpServletRequest, response, e) -> {
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json");
                    response.getWriter().println(JSONUtil.parse(Rb.a().fail().withMsg("用户名或密码错误").build()));
                    response.getWriter().flush();
                }).and()
                .logout()
                .invalidateHttpSession(true)
                //.logoutSuccessUrl("/signout/success")//退出成功后跳转的URL
                .deleteCookies("JSESSIONID")//退出成功后删除名称为JSESSIONID的cookie, 删除不成功？？？
        ;
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterAfter(purviewFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
        httpSecurity.headers().frameOptions().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return username -> {
            UserDTO user = userservice.loadUserByUserName(username);
            if (user != null) {
                UserEntity entity = new UserEntity();
                BeanUtils.copyProperties(user, entity);
                return new MyUserDetails(entity, user.getRoles());
            }
            throw new UsernameNotFoundException("用户名或密码错误");
        };
    }

    @Bean
    public PurviewFilter purviewFilter() {
        return new PurviewFilter();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}
